

#include "stdafx.h"
#include "networkModule.h"
#include "ssession.h"
#include "iocp.h"
#include "connector.h"
#include "IoPacketPool.h"

#include <process.h>


unsigned int __stdcall gRunAcceptThread( void* pParam)
{       
	IocpAccept* pIocpAccept= reinterpret_cast<IocpAccept*>(pParam);
	while( pIocpAccept->ThreadAccept() > 0 );
	return 1;
}

unsigned int __stdcall gWorkThread(void* pParam)
{
	pParam;
	while( NetworkModule::ThreadWork() >= 0 );
	return 1;
}

unsigned int __stdcall gConnectThread(void* pParam)
{
	ConnectManager* pConnectManager= reinterpret_cast<ConnectManager*>(pParam);
	while( true==pConnectManager->ThreadConnect() );
		
	return 1;
}

//////////////////////////////////////////////////////////////////////////
// NetworkModule
//////////////////////////////////////////////////////////////////////////
ConnectManager* NetworkModule::ms_pConnectManager=nullptr;
bool NetworkModule::ms_bOpen=false;
HANDLE NetworkModule::ms_hIOCP=nullptr;
HANDLE NetworkModule::ms_hIoThreads[ NetworkModule::MAX_IoTHREAD ];
HANDLE NetworkModule::ms_hConnectThread=nullptr;
int NetworkModule::ms_sizeOfIoThread=0;
IoPacketPool* NetworkModule::ms_pIoPacketPool=nullptr;

NetworkModule::NetworkModule()
{
	//CmASSERT( MAX_IoTHREAD>SIZE_WORKTHREAD );
}

NetworkModule::~NetworkModule()
{
}

void NetworkModule::initNetwork()
{
	WSADATA wsaData;
	WSAStartup( MAKEWORD( 2, 2 ), &wsaData);
	if( wsaData.wVersion != MAKEWORD( 2, 2 ) )
	{
		WSACleanup();		
	}
}

bool NetworkModule::Create()
{	
	initNetwork();
	CreateWorkThread();
	CreateConnectThread();

	if(ms_pIoPacketPool)
	{
		CmTRACE( L"already created" );
		return false;
	}
	ms_pIoPacketPool = new IoPacketPool;
	ms_pIoPacketPool->Create();
	return true;
}

void NetworkModule::Destroy()
{
	ms_pConnectManager->m_bRun = false;
	::WaitForSingleObject(ms_hConnectThread, INFINITE);
	::CloseHandle(ms_hConnectThread);
	delete ms_pConnectManager;

	//work Thread;
	for( int i=0;i<ms_sizeOfIoThread;++i)
		::PostQueuedCompletionStatus(ms_hIOCP, 0, 0, nullptr);
	::WaitForMultipleObjects(ms_sizeOfIoThread, ms_hIoThreads, true, INFINITE);
	for( int i=0;i<ms_sizeOfIoThread;++i)
		::CloseHandle(ms_hIoThreads[i]);
	
	::CloseHandle(ms_hIOCP);

	FreeManagedSession();

	ms_pIoPacketPool->Destroy();
	delete ms_pIoPacketPool;

	::WSACleanup();
}

void NetworkModule::CreateWorkThread(const int& sizeOfWorkThread)
{
	ms_sizeOfIoThread=sizeOfWorkThread;
	ms_hIOCP = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
		
	for( int i=0; i<ms_sizeOfIoThread; ++i)
	{
		HANDLE handle= CreateNetThread(gWorkThread, nullptr );			
		ms_hIoThreads[i] = handle;
		CmASSERT( NULL!=ms_hIoThreads[i] );
		CmVERIFY_RETURN(NULL!=ms_hIoThreads[i]);
	}
}

int NetworkModule::ThreadWork()
{
	HANDLE hIocpHandle = ms_hIOCP;
	BOOL bSuccess = false;
	DWORD dwIoSize = 0;
	SSession *pSession = nullptr;
	SSession::ST_IOCP_DATA *pOverlappedEx = nullptr;

	bSuccess = ::GetQueuedCompletionStatus( 
		hIocpHandle,
		&dwIoSize,				
		reinterpret_cast<PULONG_PTR>(&pSession),
		reinterpret_cast<LPOVERLAPPED*>(&pOverlappedEx),
		INFINITE );

	if( !bSuccess )
	{
		int err=::WSAGetLastError();
		if(err==ERROR_OPERATION_ABORTED)    //995L err
		{
			CmTRACE( TEXT("ERR: GetQueuedIOCP Exit IocpThread by exit\n") );
			return -1;
		}                

		if(!pOverlappedEx)
		{
			if(err!=WSA_WAIT_TIMEOUT)
			{
				err;
			}
			return 0;
		}

		if(0!=dwIoSize)
		{
			err; 
			return -1;
		}

		if(pSession)
		{
			pSession->Disconnect();
			return 0;
		}

		if( pSession != NULL && 64==err ) //64 error 
		{
			//PopSessionMap(pSession);
		}		
		return 0;
	}

	if( NULL==pOverlappedEx )
	{
		CmTRACE( TEXT("[WORK THREAD] NULL==pOverlappedEx  \n") );
		return -1;
	}

	if( NULL==pSession)
	{                
		CmTRACE( TEXT("[WORK THREAD] (iocpKey==NULL) \n") );
		return -1;
	}

	if( 0==dwIoSize &&  pOverlappedEx->_type!= SSession::eTYPE_DISCONNECT)
	{                
		CmTRACE( TEXT("INFO: GetQueuedIOCP SIZE is ZERO -> forceDisconnect. iocpType[%d] \n"), pOverlappedEx->_type );		
		return 0;   
	}

	if( SSession::eTYPE_SEND==pOverlappedEx->_type )
	{
		pSession->IOWrite(dwIoSize);
	}
	else if( SSession::eTYPE_RECV==pOverlappedEx->_type )
	{
		pSession->IOWrite(dwIoSize);
	}
	else if( SSession::eTYPE_RECV==pOverlappedEx->_type )
	{
		pSession->IODisconnect();
	}
	else	
	{
		CmTRACE( TEXT("ERR: Cannot Find Iocptype [%d] recvSize[%d]\n"), pOverlappedEx->_type, dwIoSize );
	}                
	
	return 0;
}

void NetworkModule::CreateConnectThread()
{
	if(ms_pConnectManager)
		return;

	ms_pConnectManager = new ConnectManager();
	ms_hConnectThread = CreateNetThread(gConnectThread, (LPVOID)ms_pConnectManager);
}

SSession* NetworkModule::GetNewSession()
{
	return new SSession(this);
}

void NetworkModule::ManagedSession(SSession* pSession)
{
	pSession->SetID( GenerateID() );

	m_mapSession.insert( std::make_pair(pSession->GetID(), pSession ) );
}

void NetworkModule::UnManagedSession(SSession* pSession)
{
	auto session=m_mapSession.find(pSession->GetID());
	if(session!=m_mapSession.end())
	{
		m_mapSession.erase( session );
	}
}

SSession* NetworkModule::GetSession(const int& id)
{
	auto session=m_mapSession.find(id);
	if(session!=m_mapSession.end())
		return session->second;
	return nullptr;
}

void NetworkModule::FreeManagedSession()
{
	for(auto it=m_mapSession.begin(); it!=m_mapSession.end(); ++it)
	{
		SSession* pSessoin = it->second;		
		delete pSessoin;
	}
	m_mapSession.clear();
}

HANDLE NetworkModule::CreateNetThread(THREAD_FUNC pfRun, LPVOID arg, std::wstring name)
{
	unsigned int dwThreadId=0;
#define __DEFAULT_THREAD_STACK_SIZE 0
	HANDLE handle= (HANDLE)::_beginthreadex( NULL,
		__DEFAULT_THREAD_STACK_SIZE, 
		pfRun, 
		arg, 
		0,
		&dwThreadId);

	name;
	Thread::_SetThreadName(dwThreadId, "thread");
	return handle;
}